
define(["./dom", "_"], function(dom, _) {
  var PaletteController, initialize;
  PaletteController = (function() {

    function PaletteController(id) {
      var _this = this;
      this.selected = dom(id);
      this.container = this.selected.findParent(".t-palette");
      this.available = this.container.findFirst(".t-palette-available select");
      this.hidden = this.container.findFirst("input[type=hidden]");
      this.select = this.container.findFirst("[data-action=select]");
      this.deselect = this.container.findFirst("[data-action=deselect]");
      this.moveUp = this.container.findFirst("[data-action=move-up]");
      this.moveDown = this.container.findFirst("[data-action=move-down]");
      this.reorder = this.moveUp !== null;
      this.valueToOrderIndex = {};
      _.each(this.available.element.options, function(option, i) {
        return _this.valueToOrderIndex[option.value] = i;
      });
      this.initialTransfer();
      if (!this.selected.element.disabled) {
        this.updateButtons();
        this.bindEvents();
      }
    }

    PaletteController.prototype.initialTransfer = function() {
      var e, i, movers, option, pos, value, valueToPosition, values, _i, _j, _len, _ref, _results;
      values = JSON.parse(this.hidden.value());
      valueToPosition = {};
      _.each(values, function(v, i) {
        return valueToPosition[v] = i;
      });
      e = this.available.element;
      movers = [];
      for (i = _i = _ref = e.options.length - 1; _i >= 0; i = _i += -1) {
        option = e.options[i];
        value = option.value;
        pos = valueToPosition[value];
        if (pos !== void 0) {
          movers[pos] = option;
          e.remove(i);
        }
      }
      _results = [];
      for (_j = 0, _len = movers.length; _j < _len; _j++) {
        option = movers[_j];
        _results.push(this.selected.element.add(option));
      }
      return _results;
    };

    PaletteController.prototype.updateAfterChange = function() {
      this.updateHidden();
      return this.updateButtons();
    };

    PaletteController.prototype.updateHidden = function() {
      var values;
      values = _.pluck(this.selected.element.options, "value");
      return this.hidden.value(JSON.stringify(values));
    };

    PaletteController.prototype.bindEvents = function() {
      var _this = this;
      this.container.on("change", "select", function() {
        _this.updateButtons();
        return false;
      });
      this.select.on("click", function() {
        _this.doSelect();
        return false;
      });
      this.available.on("dblclick", function() {
        _this.doSelect();
        return false;
      });
      this.deselect.on("click", function() {
        _this.doDeselect();
        return false;
      });
      this.selected.on("dblclick", function() {
        _this.doDeselect();
        return false;
      });
      if (this.reorder) {
        this.moveUp.on("click", function() {
          _this.doMoveUp();
          return false;
        });
        return this.moveDown.on("click", function() {
          _this.doMoveDown();
          return false;
        });
      }
    };

    PaletteController.prototype.updateButtons = function() {
      var nothingSelected;
      this.select.element.disabled = this.available.element.selectedIndex < 0;
      nothingSelected = this.selected.element.selectedIndex < 0;
      this.deselect.element.disabled = nothingSelected;
      if (this.reorder) {
        this.moveUp.element.disabled = nothingSelected || this.allSelectionsAtTop();
        return this.moveDown.element.disabled = nothingSelected || this.allSelectionsAtBottom();
      }
    };

    PaletteController.prototype.doSelect = function() {
      return this.transferOptions(this.available, this.selected, this.reorder);
    };

    PaletteController.prototype.doDeselect = function() {
      return this.transferOptions(this.selected, this.available, false);
    };

    PaletteController.prototype.doMoveUp = function() {
      var before, e, movers, pos;
      e = this.selected.element;
      pos = e.selectedIndex - 1;
      movers = this.removeSelectedOptions(this.selected);
      before = e.options[pos < 0 ? 0 : pos];
      return this.reorderOptions(movers, before);
    };

    PaletteController.prototype.doMoveDown = function() {
      var before, e, lastPos, lastSelected, movers;
      e = this.selected.element;
      lastSelected = _.chain(e.options).toArray().reverse().find(function(o) {
        return o.selected;
      }).value();
      lastPos = lastSelected.index;
      before = e.options[lastPos + 2];
      movers = this.removeSelectedOptions(this.selected);
      return this.reorderOptions(movers, before);
    };

    PaletteController.prototype.reorderOptions = function(movers, before) {
      var mover, _i, _len;
      for (_i = 0, _len = movers.length; _i < _len; _i++) {
        mover = movers[_i];
        this.addOption(this.selected, mover, before);
      }
      return this.updateAfterChange();
    };

    PaletteController.prototype.transferOptions = function(from, to, atEnd) {
      var movers;
      if (from.element.selectedIndex === -1) {
        return;
      }
      _(to.element.options).each(function(o) {
        return o.selected = false;
      });
      movers = this.removeSelectedOptions(from);
      return this.moveOptions(movers, to, atEnd);
    };

    PaletteController.prototype.removeSelectedOptions = function(select) {
      var e, i, movers, o, options, _i, _ref, _ref1;
      movers = [];
      e = select.element;
      options = e.options;
      for (i = _i = _ref = e.length - 1, _ref1 = e.selectedIndex; _i >= _ref1; i = _i += -1) {
        o = options[i];
        if (o.selected) {
          e.remove(i);
          movers.unshift(o);
        }
      }
      return movers;
    };

    PaletteController.prototype.moveOptions = function(movers, to, atEnd) {
      var _this = this;
      _.each(movers, function(o) {
        return _this.moveOption(o, to, atEnd);
      });
      return this.updateAfterChange();
    };

    PaletteController.prototype.moveOption = function(option, to, atEnd) {
      var before, candidate, optionOrder,
        _this = this;
      before = null;
      if (!atEnd) {
        optionOrder = this.valueToOrderIndex[option.value];
        candidate = _.find(to.element.options, function(o) {
          return _this.valueToOrderIndex[o.value] > optionOrder;
        });
        if (candidate) {
          before = candidate;
        }
      }
      return this.addOption(to, option, before);
    };

    PaletteController.prototype.addOption = function(to, option, before) {
      try {
        return to.element.add(option, before);
      } catch (ex) {
        if (before === null) {
          return to.add(option);
        } else {
          return to.add(option, before.index);
        }
      }
    };

    PaletteController.prototype.indexOfLastSelection = function(select) {
      var e, i, _i, _ref, _ref1;
      e = select.element;
      if (e.selectedIndex < 0) {
        return -1;
      }
      for (i = _i = _ref = e.options.length - 1, _ref1 = e.selectedIndex; _i >= _ref1; i = _i += -1) {
        if (e.options[i].selected) {
          return i;
        }
      }
      return -1;
    };

    PaletteController.prototype.allSelectionsAtTop = function() {
      var last, options;
      last = this.indexOfLastSelection(this.selected);
      options = _.toArray(this.selected.element.options);
      return _(options.slice(0, last + 1 || 9e9)).all(function(o) {
        return o.selected;
      });
    };

    PaletteController.prototype.allSelectionsAtBottom = function() {
      var e, last, options;
      e = this.selected.element;
      last = e.selectedIndex;
      options = _.toArray(e.options);
      return _(options.slice(last)).all(function(o) {
        return o.selected;
      });
    };

    return PaletteController;

  })();
  initialize = function(id) {
    return new PaletteController(id);
  };
  return initialize;
});
